package org.framework.lazy.cloud.network.heartbeat.server.netty.permeate.udp.socket;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.InternalNetworkServerPermeateServerRealServer;
import org.framework.lazy.cloud.network.heartbeat.common.NettyServerPermeateServerVisitorContext;
import org.framework.lazy.cloud.network.heartbeat.common.NettyVisitorPortContext;
import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelFlowAdapter;
import org.framework.lazy.cloud.network.heartbeat.common.factory.EventLoopGroupFactory;
import org.framework.lazy.cloud.network.heartbeat.server.netty.permeate.udp.filter.NettyUdpServerPermeateServerVisitorFilter;

import java.io.IOException;

/**
 * 服务端渗透服务端 访客端口
 */
@Slf4j
public class NettyUdpServerPermeateServerConnectVisitorSocket {
    private final NettyUdpServerPermeateServerVisitorFilter nettyUdpServerPermeateServerVisitorFilter;

    @Getter
    private final int visitorPort;


    public NettyUdpServerPermeateServerConnectVisitorSocket(NettyUdpServerPermeateServerVisitorFilter nettyUdpServerPermeateServerVisitorFilter,
                                                            int visitorPort) {
        this.nettyUdpServerPermeateServerVisitorFilter = nettyUdpServerPermeateServerVisitorFilter;
        this.visitorPort = visitorPort;
    }


    /**
     * 启动服务代理
     *
     * @throws Exception
     */
    public void start() throws Exception {

        NettyUdpServerPermeateServerConnectVisitorSocket nettyUdpServerPermeateServerConnectVisitorSocket = NettyServerPermeateServerVisitorContext.getServerPermeateServerVisitorSocket(visitorPort);
        if (nettyUdpServerPermeateServerConnectVisitorSocket == null) {
            ServerBootstrap bootstrap = new ServerBootstrap();
            EventLoopGroup bossGroup = EventLoopGroupFactory.createBossGroup();
            EventLoopGroup workerGroup = EventLoopGroupFactory.createWorkerGroup();
            bootstrap
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)


                    // 设置读缓冲区为2M
                    .childOption(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    // 设置写缓冲区为1M
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)


                    .childOption(ChannelOption.SO_KEEPALIVE, true)
//                    .childOption(ChannelOption.TCP_NODELAY, false)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒
//                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认 AdaptiveRecvByteBufAllocator.DEFAULT
                    .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2))


                    .childHandler(nettyUdpServerPermeateServerVisitorFilter);
            ChannelFuture sync = bootstrap.bind(visitorPort).sync();
            sync.addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    // 这里时异步处理
                    log.info("服务端渗透服务端:[{}] 开启", visitorPort);

                } else {
                    log.error("服务端渗透服务端:[{}] 开启失败", visitorPort);
                }
            });
            NettyServerPermeateServerVisitorContext.pushServerPermeateServerVisitorSocket(visitorPort, this);

        } else {
            log.warn("内网渗透服务端端口:[{}] 重复启动", visitorPort);
        }

    }

    public void close() throws IOException, InterruptedException {
        Channel visitor = NettyVisitorPortContext.getVisitorChannel(visitorPort);
        if (visitor != null) {
            // close channel
            visitor.close();
            NettyServerPermeateServerVisitorContext.removeServerPermeateServerVisitorSockets(visitorPort);
//            log.warn("关闭客户端 :【{}】 访客户端口:【{}】", clientId, visitorPort);
        } else {
            log.warn("关闭内网渗透端口失败  渗透端口:【{}】", visitorPort);
        }
    }


    public static final class NettyPermeateVisitorSocketBuilder {


        /**
         * 客户端目标地址
         */
        private String clientTargetIp;

        /**
         * 客户端目标端口
         */
        private Integer clientTargetPort;


        /**
         * 访问端口
         */
        private Integer permeateVisitorPort;

        /**
         * 是否是ssl
         */
        private Boolean isSsl;

        /**
         * 流量适配器
         */
        private ChannelFlowAdapter channelFlowAdapter;

        public static NettyPermeateVisitorSocketBuilder builder() {
            return new NettyPermeateVisitorSocketBuilder();
        }

        /**
         * 绑定客户端目标IP
         *
         * @param clientTargetIp 客户端目标IP
         * @return 当前对象
         */
        public NettyPermeateVisitorSocketBuilder builderClientTargetIp(String clientTargetIp) {
            this.clientTargetIp = clientTargetIp;
            return this;
        }

        /**
         * 绑定客户端目标端口
         *
         * @param clientTargetPort 客户端目标端口
         * @return 当前对象
         */
        public NettyPermeateVisitorSocketBuilder builderClientTargetPort(Integer clientTargetPort) {
            this.clientTargetPort = clientTargetPort;
            return this;
        }

        /**
         * 绑定访客端口
         *
         * @param permeateVisitorPort 访客端口
         * @return 当前对象
         */
        public NettyPermeateVisitorSocketBuilder builderVisitorPort(Integer permeateVisitorPort) {
            this.permeateVisitorPort = permeateVisitorPort;
            return this;
        }

        /**
         * 绑定流量适配器
         *
         * @param channelFlowAdapter 流量适配器
         * @return 当前对象
         */
        public NettyPermeateVisitorSocketBuilder builderChannelFlowAdapter(ChannelFlowAdapter channelFlowAdapter) {
            this.channelFlowAdapter = channelFlowAdapter;
            return this;
        }

        /**
         * 是否是ssl
         *
         * @param isSsl 是否是ssl
         * @return 当前对象
         */
        public NettyPermeateVisitorSocketBuilder builderIsSsl(Boolean isSsl) {
            this.isSsl = isSsl;
            return this;
        }


        public NettyUdpServerPermeateServerConnectVisitorSocket build() {

            if (clientTargetIp == null) {
                throw new IllegalArgumentException("clientTargetIp must not null");
            }
            if (clientTargetPort == null) {
                throw new IllegalArgumentException("clientTargetPort must not null");
            }
            if (permeateVisitorPort == null) {
                throw new IllegalArgumentException("visitorPort must not null");
            }
            InternalNetworkServerPermeateServerRealServer internalNetworkServerPermeateServerRealServer = InternalNetworkServerPermeateServerRealServer
                    .builder()
                    .clientTargetIp(clientTargetIp)
                    .clientTargetPort(clientTargetPort)
                    .visitorPort(permeateVisitorPort)
                    .isSsl(isSsl)
                    .build();

            NettyUdpServerPermeateServerVisitorFilter nettyUdpServerPermeateServerVisitorFilter = new NettyUdpServerPermeateServerVisitorFilter(internalNetworkServerPermeateServerRealServer, channelFlowAdapter);
            return new NettyUdpServerPermeateServerConnectVisitorSocket(nettyUdpServerPermeateServerVisitorFilter, permeateVisitorPort);
        }


    }

}
